package com.aplikata.evok.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.myfaces.custom.fileupload.UploadedFile;
import org.primefaces.model.DefaultScheduleEvent;
import org.primefaces.model.ScheduleEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.aplikata.bo.Node;
import com.aplikata.bo.Role;
import com.aplikata.bo.User;
import com.aplikata.bo.UserReference;
import com.aplikata.constants.Constants;
import com.aplikata.constants.ConstantsMsg;
import com.aplikata.dao.NodeDao;
import com.aplikata.dao.UserEventDao;
import com.aplikata.evok.bo.ContactPerson;
import com.aplikata.evok.bo.DoctorSchedule;
import com.aplikata.evok.bo.DomainPatient;
import com.aplikata.evok.bo.Patient;
import com.aplikata.evok.bo.PatientAttachement;
import com.aplikata.evok.bo.PatientNode;
import com.aplikata.evok.constants.EvokConstants;
import com.aplikata.evok.dao.PatientDao;
import com.aplikata.exception.CustomException;
import com.aplikata.service.PublicServiceImpl;
import com.aplikata.util.FacesUtil;
import com.aplikata.util.FileUtil;
import com.aplikata.util.StringUtil;
import com.aplikata.util.YunDateUtil;
import com.aplikata.util.encoder.MD5PasswordEncoder;
import com.aplikata.util.encoder.PasswordEncoder;

/**
 * @ClassName: EvokPatientServiceImpl
 * @Description: TODO
 * @author Huyun
 * @date 17. 5. 2012. 09:23:58
 */
@Service("evokPatientService")
public class EvokPatientServiceImpl extends PublicServiceImpl implements EvokPatientService {
	private static Log errorlog = LogFactory.getLog(EvokPatientServiceImpl.class);

	@Autowired
	private NodeDao nodeDao;

	@Autowired
	private PatientDao patientDao;

	@Autowired
	private UserEventDao userEventDao;

	public EvokPatientServiceImpl() {
	}

	@SuppressWarnings("unchecked")
	@Override
	public DomainPatient updatePatient(boolean readonly, Patient patient, DomainPatient domainPatient, String userName,
			List<PatientNode> patientNodeList) throws Exception {
		if (patient == null)
			return null;

		Long tempId = patient.getId();
		Long tempId1 = domainPatient.getId();

		if (!readonly) {
			String emailpassword = "";
			patientDao.validate(patient);

			if (StringUtil.isStrEmpty(userName)) {
				throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("login_user") });
			}

			patient.setOperUser(FacesUtil.getUserFromSession());
			patient.setOperTime(YunDateUtil.getDateTime());

			if (!StringUtil.isStrEmpty(userName)) {
				User user = null;
				User userOld = null;
				String hql = " from User u where u.userName = '" + userName + "'";
				if (!FacesUtil.isKeyNull(tempId)) {
					user = (User) findSingleByNamedQuery(Patient.QY_FIND_USER, new Object[] { tempId });
				}

				if (user != null) {
					hql += " and u.id != " + user.getId();
					userOld = user;
				}

				user = (User) getPublicDao().getFirstRow(hql);

				if (user != null)
					throw new CustomException("error_exist", new Object[] { user.getUserName() });

				if (userOld == null) {
					userOld = new User();
					userOld.setUserName(userName);

					PasswordEncoder encoder = new MD5PasswordEncoder();
					emailpassword = Constants.DEFAULT_USER_PASSWORD;
					userOld.setUserPwd(encoder.encode(emailpassword));
					userOld.setStatus(Constants.COMMON_STATUS_NORMAL);

					Role role = (Role) getPublicDao().findSingleByProperty(Role.class, Role.NAME,
							EvokConstants.ROLE_PATIENT);
					userOld.setRole(role);
					userOld.setEmail(domainPatient.getEmail1());
					userOld = (User) getPublicDao().merge(userOld);
					patient.setUser(userOld);
				} else {
					userOld.setUserName(userName);
					userOld.setEmail(domainPatient.getEmail1());
					userOld = (User) getPublicDao().merge(userOld);
				}

				UserReference ref = userOld.getUserReference();
				if (ref == null) {
					ref = new UserReference();
					ref.setSendEmail(true);
				}

				ref.setUser(userOld);
				ref.setSurname(patient.getSurname());
				ref.setName(patient.getName());
				ref.setSex(patient.getSex());
				
				userOld.setUserReference(ref);
				userOld = (User) getPublicDao().merge(userOld);

				// set user to session
				if (userOld.getId().equals(FacesUtil.getUserFromSession().getId())) {
					FacesUtil.setManagedBeanInSession(Constants.SESSION_USER, userOld);
				}
			}

			patient = (Patient) getPublicDao().merge(patient);
		}

		domainPatient.setDomain(FacesUtil.getDomainFromSession());
		domainPatient.setPatient(patient);
		if (domainPatient.getRegistDate() == null) {
			domainPatient.setRegistDate(YunDateUtil.getDate());
		}
		domainPatient.setUser(FacesUtil.getUserFromSession());
		domainPatient.setOperTime(YunDateUtil.getDateTime());
		domainPatient = (DomainPatient) getPublicDao().merge(domainPatient);
		Long domainPatientId = domainPatient.getId();

		if (!FacesUtil.isKeyNull(tempId1)) {
			if (patientNodeList == null || patientNodeList.isEmpty())
				return domainPatient;

			String str = "";
			String nodestr = "";

			for (PatientNode pn : patientNodeList) {
				Node node = pn.getNode();
				String value = pn.getValue();

				nodestr += node.getId() + ",";

				if (nodeDao.validateDynamicNode(node, value)) {
					if (!StringUtil.isStrEmpty(value)) {
						str += "(" + domainPatientId + "," + node.getId() + ",'" + value + "'),";
					}
				}
			}

			if (!StringUtil.isStrEmpty(nodestr)) {
				String deletesql = " delete from evk_patient_node where domain_patient_id = " + domainPatientId;
				if (nodestr.endsWith(",")) {
					nodestr = nodestr.substring(0, nodestr.lastIndexOf(","));
				}
				deletesql = deletesql + " and node_id in (" + nodestr + ")";
				getPublicDao().updateBySql(deletesql);
			}

			String insertsql = " insert into evk_patient_node (domain_patient_id, node_id, value) values ";

			if (StringUtil.isStrEmpty(str))
				return domainPatient;

			if (str.endsWith(",")) {
				str = str.substring(0, str.lastIndexOf(","));
			}
			getPublicDao().updateBySql(insertsql + str);
		}

		return domainPatient;
	}

	@Override
	public List<ScheduleEvent> findPatientAllCalendar(Long patientId, Date dateFrom, Date dateTo) {
		List<ScheduleEvent> newlist = new ArrayList<ScheduleEvent>();

		List<ScheduleEvent> privatelist = userEventDao.getUserEventList(patientId, dateFrom, dateTo);
		if (privatelist != null && !privatelist.isEmpty())
			newlist.addAll(privatelist);

		List<DoctorSchedule> reslist = getPatientResversationInCanlendar(patientId, dateFrom, dateTo);

		if (reslist == null || reslist.isEmpty())
			return newlist;

		List<ScheduleEvent> rslist = new ArrayList<ScheduleEvent>();
		for (DoctorSchedule res : reslist) {
			User user = res.getOper();
			UserReference doctor = res.getDoctor().getUserReference();
			DefaultScheduleEvent temp = new DefaultScheduleEvent(user.getDomain().getName() + " - "
					+ doctor.getSurname() + " " + doctor.getName() + ": " + res.getContent(), res.getTimeFrom(),
					res.getTimeTo(), res);

			temp.setStyleClass("doctor_reservation");
			if (res.isPriority())
				temp.setStyleClass("doctor_reservation_priority");

			rslist.add(temp);
		}

		newlist.addAll(rslist);
		return newlist;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<DoctorSchedule> getPatientResversationInCanlendar(Long patientUserId, Date dateFrom, Date dateTo) {
		String sql = "SELECT {e.*} FROM evk_doctor_schedule e, evk_domain_patient dp, evk_patient p "
				+ " WHERE e.domain_patient_id = dp.id and dp.patient_id = p.id and p.user_id = " + patientUserId
				+ " AND e.status != " + EvokConstants.DOC_RESERVATION_STATUS_CANCEL + " AND e.time_from >= '"
				+ YunDateUtil.formatDate(dateFrom) + "'" + " AND e.time_from <= '" + YunDateUtil.formatDate(dateTo)
				+ "' order by e.time_from";

		return getPublicDao().getSQLQuery(sql).addEntity("e", DoctorSchedule.class).list();
	}

	@Override
	public Object[] getTherapyObjForCalendar(Long patientTherapyId) {
		String sql = "SELECT t.start_date, group_concat(et.name separator ' | '), t.status, t.id "
				+ " FROM evk_patient_therapy t, evk_patient_therapy_category c, evk_therapy et"
				+ " WHERE c.patient_therapy_id = t.id and c.therapy_id = et.id" + " AND t.id = " + patientTherapyId
				+ " GROUP BY t.id";

		return (Object[]) this.findSingleBySql(sql);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> getPatientTodoList(Long patientUserId) {
		String sql;

		String privatesql = " SELECT u.title, u.time_from, u.time_to "
				+ " FROM _user_event u where u.time_to > now() AND u.user_id = " + patientUserId;

		String ressql = " SELECT concat(d.domain_name, '<br/>' , uf.surname, ' ', uf.ime, '<br/>', s.content), s.time_from, s.time_to "
				+ " FROM evk_doctor_schedule s, evk_domain_patient dp, evk_patient p, _user_reference uf , _domain d"
				+ " WHERE s.domain_patient_id = dp.id "
				+ " AND dp.domain_id = d.id "
				+ " AND dp.patient_id = p.id "
				+ " AND s.doctor_id = uf.user_id" + " AND s.time_to > now()" + " AND p.user_id = " + patientUserId;

		sql = "Select u.* from (" + privatesql + " union " + ressql + ") u order by u.time_from";

		return getPublicDao().findBySql(sql);
	}

	@SuppressWarnings("unchecked")
	@Override
	public PatientAttachement submitPatientAttachement(PatientAttachement patientAtt, UploadedFile att)
			throws Exception {
		if (StringUtil.isStrEmpty(patientAtt.getDescription())) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE,
					new Object[] { FacesUtil.getMessage("msg_headline") });
		}
		if (FacesUtil.isKeyNull(patientAtt.getId())) {
			patientAtt.setId(null);
			patientAtt.setCreateTime(YunDateUtil.getDateTime());
		}

		if (FacesUtil.isKeyNull(patientAtt.getId()) && att == null) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE,
					new Object[] { FacesUtil.getMessage("default_document") });
		}

		if (att != null) {
			String attname = "";
			attname = FileUtil.getFileName(att.getName().replace(' ', '_'));
			attname = FileUtil.utf8ToLatin(attname);
			attname = attname.substring(attname.lastIndexOf("\\") + 1, attname.length());
			if (attname.length() > 150) {
				attname = attname.substring(0, attname.length() - 1);
			}
			patientAtt.setFileName(attname);

			attname = "dm" + FacesUtil.getDomainFromSession().getId().toString() + "-"
					+ patientAtt.getDomainPatient().getId() + "-" + YunDateUtil.formatDateTime("yyyyMMddHHmmss") + "-"
					+ attname;
			String filename = FacesUtil.getServletContext().getRealPath(
					(new StringBuilder("/upload\\patient\\")).append(attname).toString());
			patientAtt.setFilePath(FacesUtil.getServletContext().getContextPath() + "/upload/patient/" + attname);
			FileUtil.writeToFile(att.getInputStream(), filename);
			patientAtt.setCreateTime(YunDateUtil.getDateTime());
		}

		return (PatientAttachement) getPublicDao().merge(patientAtt);
	}

	@SuppressWarnings("unchecked")
	@Override
	public void deletePatientAttachement(PatientAttachement patientAtt) throws Exception {
		if (patientAtt == null || FacesUtil.isKeyNull(patientAtt.getId()))
			return;

		getPublicDao().delete(patientAtt);
	}

	@SuppressWarnings("unchecked")
	@Override
	public ContactPerson updatePatientContactPerson(ContactPerson contactPerson) throws Exception {
		if (contactPerson == null) {
			return null;
		}

		if (FacesUtil.isKeyNull(contactPerson.getRelationship())) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE,
					new Object[] { FacesUtil.getMessage("evok_contact_person_relationship") });
		}

		if (StringUtil.isStrEmpty(contactPerson.getSurname())) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("empl_surname") });
		}

		if (StringUtil.isStrEmpty(contactPerson.getName())) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("empl_name") });
		}

		if (StringUtil.isStrEmpty(contactPerson.getStreet())) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("empl_street") });
		}

		if (contactPerson.getCity() == null) {
			throw new CustomException(ConstantsMsg.MSG_REQUIRE, new Object[] { FacesUtil.getMessage("empl_liveplace") });
		}

		return (ContactPerson) getPublicDao().merge(contactPerson);
	}
}
